import 'dart:typed_data';

import 'package:dartx/dartx.dart';
import 'package:sgy_flutter/ble/ext.dart';
import 'package:sgy_flutter/ble/sgy_cmd.dart';

class Packet {
  static const header = [0x55, 0xaa];
  SgyCMD cmd = SgyCMD.unknow;
  int dataLength = -1;
  int crc = -1;
  List<int> data = [];

  Packet({required this.cmd, required this.data}) {
    dataLength = data.length;
    crc = CRC(data: data);
  }

  static Packet fromBleData(Uint8List data) {
    if (data.length >= 8) {
      final byteData = data.buffer.asByteData();
      final fromHeader = [byteData.getUint8(0), byteData.getUint8(1)];
      if (fromHeader.contentEquals(header)) {
        final fromCmd = [byteData.getUint8(2), byteData.getUint8(3)];

        final fromDataLength = byteData.getInt16(4, Endian.little);
        final fromCRC = byteData.getInt16(6, Endian.little);
        List<int> fromData = List.empty(growable: true);
        fromData.addAll(data.skip(8));

        if (fromData.length == fromDataLength) {
          final cmd = SgyCMD.from(fromCmd);
          final packet = Packet(cmd: cmd, data: fromData);
          packet.dataLength = fromDataLength;
          packet.data = fromData;
          final crc = CRC(data: fromData);
          if (crc == fromCRC) {
            packet.crc = fromCRC;
          }
          return packet;
        } else {
          throw RangeError("业务数据长度错误:${fromData.length}");
        }
      } else {
        throw RangeError(
            "数据头错误:${fromHeader.toHex()},原始数据:${data.toHex()}");
      }
    } else {
      throw RangeError("数据长度错误:${data.length}");
    }
  }

  Uint8List toByteArray() {
    List<int> byteArray = List<int>.empty(growable: true);
    byteArray += header;
    byteArray += cmd.array;
    byteArray += dataLength.bytes();
    byteArray += crc.bytes();
    byteArray += data;
    return Uint8List.fromList(byteArray);
  }
}

///CRC16校验  list是需要增加校验位的数据
int CRC({ int poly = 0x8005,
  int init = 0xffff,
  required List<int> data,
  int offset = 0,
  bool refin = true,
  bool refout = true,
  int xorout = 0x0000}) {
  int length = data.length;
  int crc = init;

  for (int i = offset; i < offset + length && i < data.length; ++i) {
    int b = data[i];

    for (int j = 0; j < 8; ++j) {
      int k = refin ? 7 - j : j;
      bool bit = (b >> 7 - k & 1) == 1;
      bool c15 = (crc >> 15 & 1) == 1;
      crc <<= 1;
      if (c15 ^ bit) {
        crc ^= poly;
      }
    }
  }
  int reverseBytes(int var0) {
    return var0 << 24 | (var0 & 0xff00) << 8 | var0 >>> 8 & 0xff00 | var0 >>>
        24;
  }
  int reverse(int var0) {
    var0 = (var0 & 1431655765) << 1 | var0 >>> 1 & 1431655765;
    var0 = (var0 & 858993459) << 2 | var0 >>> 2 & 858993459;
    var0 = (var0 & 252645135) << 4 | var0 >>> 4 & 252645135;
    return reverseBytes(var0);
  }
  return refout
      ? reverse(crc) >>> 16 ^ xorout
      : (crc ^ xorout) & 0xffff;
}
